AJAX Elements in Selenium
AJAX (Asynchronous JavaScript and XML) is a web development technique that allows web pages to communicate with a server asynchronously and update specific parts of the page without requiring a complete page reload. Modern web applications frequently use AJAX, JavaScript, Fetch API, XMLHttpRequest, and similar technologies to load or modify content dynamically.
For Selenium automation, AJAX elements are important because an element may not immediately exist, become visible, become enabled, or contain the expected data when Selenium first tries to interact with it. Selenium's documentation notes that JavaScript-driven changes can occur after the initial page load, creating synchronization problems if the automation executes before the application reaches the required state. :contentReference[oaicite:0]{index=0}
To automate AJAX-based applications reliably, Selenium tests commonly use Explicit Waits, Expected Conditions, appropriate locators, and other synchronization techniques rather than relying on fixed delays.
Course Resource: Selenium Training | Register for Course Demo
1. What is AJAX?
AJAX stands for Asynchronous JavaScript and XML. It is a technique used by web applications to exchange data with a server asynchronously and update part of a webpage without refreshing the complete page.
Although the name contains XML, modern applications commonly exchange data using JSON, and JavaScript may use APIs such as Fetch or XMLHttpRequest.
For example, when a user types a product name into a search box, the application may send a background request to the server and display matching products without reloading the entire page.
User enters data
|
v
JavaScript event
|
v
AJAX / Fetch Request
|
v
Server processes request
|
v
Response returned
|
v
DOM updated dynamically
|
v
New/updated element available
2. Why are AJAX Elements Important in Selenium?
AJAX elements are important because Selenium automation can encounter a timing difference between the browser application and the test script.
The page's initial document may already be loaded while JavaScript is still adding elements, changing their visibility, updating text, loading data, or enabling controls.
- Elements may appear after a delay.
- Elements may become visible only after an AJAX response.
- Buttons may initially be disabled and become enabled later.
- Text may be updated dynamically.
- Tables may receive rows asynchronously.
- Dropdown options may be loaded dynamically.
- Search suggestions may appear after typing.
- Loading indicators may disappear after a server response.
- DOM elements may be replaced during asynchronous updates.
- Single Page Applications may continuously update the DOM.
3. AJAX Element Execution Flow
Test Starts
|
v
Open Web Application
|
v
Initial DOM Loaded
|
v
JavaScript Executes
|
v
AJAX / Fetch Request
|
v
Server Response
|
v
DOM Updated
|
v
Element Becomes Ready
|
v
Explicit Wait Condition Satisfied
|
v
Selenium Interacts with Element
|
v
Assertion
4. Static vs AJAX Elements
| Static Element | AJAX/Dynamic Element |
| Usually available immediately | May appear later |
| Content changes less frequently | Content can change dynamically |
| Simple synchronization may be enough | Explicit synchronization is often required |
| Usually present in initial DOM | May be added or modified after JavaScript execution |
| Less likely to create timing problems | More likely to create timing problems |
5. Example of an AJAX Element
Consider a search application where a user enters "Laptop". The application sends an asynchronous request and displays search suggestions.
User types: Laptop
|
v
AJAX request
|
v
Server searches products
|
v
Response received
|
v
Suggestion list updated
|
v
Laptop Pro
Laptop Stand
Laptop Bag
The suggestion elements may not exist at the exact moment the user finishes typing. Selenium therefore needs to synchronize with the application's state.
6. Why Thread.sleep() is Not the Best Solution
A common approach is to use Thread.sleep() after performing an AJAX action.
driver.findElement(By.id("search")).sendKeys("Laptop");
Thread.sleep(5000);
driver.findElement(By.id("result")).click();
This approach is generally inefficient because the test waits for the full duration even if the element becomes ready earlier. If the application takes longer than the hard-coded duration, the test can still fail.
Selenium recommends condition-based synchronization such as explicit waits for dynamic applications. :contentReference[oaicite:1]{index=1}
7. Explicit Wait for AJAX Elements
An Explicit Wait waits for a specific condition before continuing test execution.
WebDriverWait wait = new WebDriverWait(
driver,
Duration.ofSeconds(10)
);
WebElement element = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("result")
)
);
element.click();
Explicit waits are particularly useful for AJAX elements because the test can wait for the actual condition rather than an arbitrary amount of time. Selenium describes explicit waits as polling for a specific condition until it becomes true or the timeout is reached. :contentReference[oaicite:2]{index=2}
8. Expected Conditions for AJAX Elements
Selenium provides commonly used Expected Conditions for explicit waits. These include conditions for element presence, visibility, clickability, text, titles, and other states. :contentReference[oaicite:3]{index=3}
| Expected Condition | Purpose |
| presenceOfElementLocated() | Waits until the element exists in the DOM |
| visibilityOfElementLocated() | Waits until the element is visible |
| elementToBeClickable() | Waits until the element can be clicked |
| textToBePresentInElement() | Waits for expected text |
| titleContains() | Waits for a title containing specific text |
| stalenessOf() | Waits until an old element reference is no longer attached to the DOM |
| invisibilityOfElementLocated() | Waits until an element becomes invisible |
9. presenceOfElementLocated()
This condition waits until an element is present in the DOM. Presence does not necessarily mean that the element is visible or interactable.
WebDriverWait wait = new WebDriverWait(
driver,
Duration.ofSeconds(10)
);
WebElement result = wait.until(
ExpectedConditions.presenceOfElementLocated(
By.id("ajaxResult")
)
);
Use this when the main requirement is that the element exists in the DOM.
10. visibilityOfElementLocated()
This condition waits until an element is present and visible.
WebElement result = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("ajaxResult")
)
);
System.out.println(result.getText());
This is useful when AJAX content is inserted into the DOM but becomes visible only after a background operation completes.
11. elementToBeClickable()
Sometimes an AJAX button is present but cannot yet be interacted with. In such situations, waiting for clickability can be useful.
WebElement submitButton = wait.until(
ExpectedConditions.elementToBeClickable(
By.id("submit")
)
);
submitButton.click();
Selenium's troubleshooting documentation specifically identifies explicit waits and clickability conditions as useful for synchronization problems. :contentReference[oaicite:4]{index=4}
12. Waiting for AJAX Text
AJAX applications often update text after receiving a server response.
wait.until(
ExpectedConditions.textToBePresentInElementLocated(
By.id("status"),
"Success"
)
);
System.out.println(
driver.findElement(By.id("status")).getText()
);
This is useful for status messages such as "Loading", "Processing", "Success", "Order Placed", or "Data Loaded".
13. Waiting for AJAX Loading Indicator
Many modern applications display a loading spinner while an asynchronous operation is running.
WebDriverWait wait = new WebDriverWait(
driver,
Duration.ofSeconds(15)
);
driver.findElement(By.id("search")).sendKeys("Laptop");
wait.until(
ExpectedConditions.invisibilityOfElementLocated(
By.id("loadingSpinner")
)
);
WebElement result = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("searchResult")
)
);
System.out.println(result.getText());
This approach waits for the application to finish its loading state before interacting with the result.
14. AJAX Search Suggestions
Autocomplete and search suggestion fields are common AJAX scenarios.
WebDriverWait wait = new WebDriverWait(
driver,
Duration.ofSeconds(10)
);
WebElement search = driver.findElement(
By.id("search")
);
search.sendKeys("Selenium");
WebElement suggestion = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.xpath("//li[contains(text(),'Selenium')]")
)
);
suggestion.click();
15. AJAX Dropdowns
Some dropdowns retrieve their options dynamically after the user selects another field.
driver.findElement(By.id("country"))
.click();
WebDriverWait wait = new WebDriverWait(
driver,
Duration.ofSeconds(10)
);
WebElement state = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("state")
)
);
state.click();
For example, selecting a country may trigger an AJAX request that loads the corresponding states.
16. AJAX Dependent Dropdown Flow
Select Country
|
v
AJAX Request
|
v
Server Returns States
|
v
State Dropdown Updated
|
v
Wait for State Option
|
v
Select State
17. Waiting for Dynamic Table Rows
Tables are frequently populated using AJAX calls.
WebDriverWait wait = new WebDriverWait(
driver,
Duration.ofSeconds(10)
);
driver.findElement(By.id("loadUsers")).click();
wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.xpath("//table[@id='users']//tbody/tr")
)
);
List<WebElement> rows = driver.findElements(
By.xpath("//table[@id='users']//tbody/tr")
);
System.out.println("Rows: " + rows.size());
18. AJAX Pagination
Some applications load the next page of records without performing a full browser navigation.
driver.findElement(By.id("nextPage")).click();
wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.xpath("//table[@id='users']//tbody/tr")
)
);
System.out.println(
driver.findElement(By.id("pageNumber")).getText()
);
The important point is to wait for a meaningful change in the page state rather than simply assuming that the next page is ready immediately.
19. AJAX Buttons
An AJAX button may initiate a background request and change its state.
WebElement saveButton = wait.until(
ExpectedConditions.elementToBeClickable(
By.id("save")
)
);
saveButton.click();
wait.until(
ExpectedConditions.textToBePresentInElementLocated(
By.id("message"),
"Saved"
)
);
20. AJAX Form Submission
Some forms submit data asynchronously without navigating to another page.
driver.findElement(By.id("name"))
.sendKeys("John");
driver.findElement(By.id("email"))
.sendKeys("[email protected]");
driver.findElement(By.id("submit"))
.click();
wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("successMessage")
)
);
Assert.assertEquals(
driver.findElement(By.id("successMessage")).getText(),
"Registration Successful"
);
21. AJAX Login
Some login forms authenticate users asynchronously and update the current page rather than performing a complete navigation.
driver.findElement(By.id("username"))
.sendKeys("admin");
driver.findElement(By.id("password"))
.sendKeys("admin123");
driver.findElement(By.id("login"))
.click();
wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("dashboard")
)
);
Assert.assertTrue(
driver.findElement(By.id("dashboard")).isDisplayed()
);
22. AJAX Cart Updates
E-commerce websites often update cart counts asynchronously.
driver.findElement(By.id("addToCart"))
.click();
wait.until(
ExpectedConditions.textToBePresentInElementLocated(
By.id("cartCount"),
"1"
)
);
System.out.println(
driver.findElement(By.id("cartCount")).getText()
);
23. AJAX Notifications
Applications may display notifications dynamically after an operation.
driver.findElement(By.id("save"))
.click();
WebElement notification = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.className("notification")
)
);
System.out.println(
notification.getText()
);
24. AJAX Modal Windows
AJAX requests may dynamically create modal dialogs.
driver.findElement(By.id("openModal"))
.click();
WebElement modal = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("userModal")
)
);
modal.findElement(
By.id("confirm")
).click();
25. AJAX Tabs
Some tabbed interfaces load content only when a tab is selected.
driver.findElement(By.id("ordersTab"))
.click();
WebElement orders = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("ordersContent")
)
);
System.out.println(
orders.getText()
);
26. AJAX and StaleElementReferenceException
AJAX updates can replace DOM elements. When an element that Selenium previously located is removed and replaced, the old WebElement reference may become invalid. This can result in a StaleElementReferenceException.
WebElement button = driver.findElement(
By.id("refresh")
);
button.click();
button.click();
The second operation can fail if the AJAX update replaced the original element.
27. Handling Stale Elements
A useful approach is to locate the element again after the DOM update.
driver.findElement(By.id("refresh"))
.click();
WebElement button = wait.until(
ExpectedConditions.elementToBeClickable(
By.id("refresh")
)
);
button.click();
Another approach is to use a wait that explicitly waits for the old element to become stale and then locates the replacement element.
28. stalenessOf()
The stalenessOf() condition waits until a previously located element is no longer attached to the DOM.
WebElement oldElement = driver.findElement(
By.id("data")
);
driver.findElement(By.id("refresh"))
.click();
wait.until(
ExpectedConditions.stalenessOf(oldElement)
);
WebElement newElement = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("data")
)
);
This can be useful when an AJAX operation replaces existing content.
29. AJAX and NoSuchElementException
If Selenium searches for an AJAX-generated element before it has been added to the DOM, a NoSuchElementException can occur.
driver.findElement(By.id("load"))
.click();
driver.findElement(By.id("dynamicElement"))
.click();
The solution is generally to synchronize with the condition that indicates the element is ready.
driver.findElement(By.id("load"))
.click();
WebElement dynamicElement = wait.until(
ExpectedConditions.elementToBeClickable(
By.id("dynamicElement")
)
);
dynamicElement.click();
30. AJAX and ElementNotInteractableException
An element can exist in the DOM but still not be ready for interaction. For example, an element may be hidden until an AJAX operation completes.
WebElement element = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("dynamicInput")
)
);
element.sendKeys("Selenium");
Waiting for visibility or clickability is generally more reliable than assuming that DOM presence means the element is ready.
31. AJAX and JavaScript Execution
JavaScript can be used to inspect the current document state or interact with application-specific JavaScript when appropriate. However, JavaScript execution should not replace proper synchronization.
JavascriptExecutor js =
(JavascriptExecutor) driver;
String state = (String) js.executeScript(
"return document.readyState;"
);
System.out.println("State: " + state);
The document.readyState describes document loading, but Selenium's documentation points out that a complete ready state does not guarantee that JavaScript-driven application content has finished loading. :contentReference[oaicite:5]{index=5}
32. document.readyState and AJAX
A common misconception is that document.readyState = complete means every AJAX operation has completed.
document.readyState
Possible values include:
- loading: The document is still loading.
- interactive: The document has been parsed and is interactive.
- complete: The document and its initial resources have completed loading.
However, asynchronous JavaScript can continue changing the page after the initial document reaches its ready state. :contentReference[oaicite:6]{index=6}
33. AJAX vs Page Load
| Page Load | AJAX Operation |
| Usually associated with navigation | Usually occurs asynchronously within the current page |
| Document loading is involved | Specific content may be updated |
| WebDriver navigation waits according to page-load strategy | Additional synchronization may be required |
| May replace the entire document | Usually changes part of the DOM |
34. AJAX in Single Page Applications
Single Page Applications, or SPAs, frequently update content dynamically without performing traditional full-page navigation.
Examples of technologies commonly used in modern applications include React, Angular, Vue, and other JavaScript frameworks.
User Action
|
v
JavaScript Event
|
v
API Request
|
v
Response
|
v
Application State Updated
|
v
DOM Re-rendered
|
v
Selenium Interacts with New State
Because the DOM can change after the initial page load, synchronization is particularly important in SPA automation.
35. AJAX and React Applications
React applications can dynamically render and re-render components. Selenium should therefore wait for observable application conditions rather than relying only on page navigation completion.
driver.findElement(By.id("loadProducts"))
.click();
WebElement product = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.cssSelector(".product-card")
)
);
System.out.println(
product.getText()
);
36. AJAX and Angular Applications
Angular applications can also perform asynchronous requests and update components dynamically.
driver.findElement(By.id("search"))
.sendKeys("Laptop");
WebElement result = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.cssSelector(".search-result")
)
);
result.click();
37. AJAX and Vue Applications
Vue-based applications can dynamically update components after user interactions or API responses.
driver.findElement(By.id("loadUsers"))
.click();
wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.cssSelector(".user-row")
)
);
List<WebElement> users = driver.findElements(
By.cssSelector(".user-row")
);
System.out.println(users.size());
38. AJAX and Dynamic Locators
Dynamic applications may generate changing IDs or classes. In such situations, stable attributes and meaningful locator strategies should be preferred.
By result = By.xpath(
"//div[contains(@class,'result')]"
);
WebElement element = wait.until(
ExpectedConditions.visibilityOfElementLocated(result)
);
Good locator strategies help Selenium find dynamically generated elements reliably.
39. AJAX and CSS Selectors
CSS selectors can be useful for locating dynamic elements.
WebElement result = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.cssSelector(".search-results .item")
)
);
40. AJAX and XPath
XPath can be useful when the dynamic element must be located using text or relationships.
WebElement result = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.xpath("//div[contains(text(),'Selenium')]")
)
);
41. Waiting for Number of AJAX Results
Sometimes the test needs to wait until multiple elements are loaded.
wait.until(
ExpectedConditions.numberOfElementsToBeMoreThan(
By.cssSelector(".product"),
0
)
);
List<WebElement> products =
driver.findElements(
By.cssSelector(".product")
);
This approach can be useful for dynamically populated product lists or search results.
42. Waiting for AJAX Attribute Changes
AJAX operations may change an element's attributes.
wait.until(driver -> {
String value = driver.findElement(
By.id("status")
).getAttribute("class");
return value != null &&
value.contains("completed");
});
Custom conditions can be useful when the application's state is represented by an attribute that does not have a built-in Expected Condition.
43. Custom Explicit Wait Condition
Java Selenium allows a custom condition to be implemented using a lambda expression.
WebDriverWait wait = new WebDriverWait(
driver,
Duration.ofSeconds(10)
);
wait.until(driver -> {
String text = driver.findElement(
By.id("status")
).getText();
return text.equals("Completed");
});
Explicit waits can poll the application until the required condition becomes true. :contentReference[oaicite:7]{index=7}
44. Fluent Wait for AJAX Elements
FluentWait allows control over timeout, polling interval, and ignored exceptions.
Wait<WebDriver> wait =
new FluentWait<WebDriver>(driver)
.withTimeout(Duration.ofSeconds(15))
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoSuchElementException.class);
WebElement element = wait.until(
driver -> driver.findElement(
By.id("dynamicElement")
)
);
This can be useful in advanced synchronization scenarios where a custom polling strategy is needed.
45. Implicit Wait with AJAX
An implicit wait tells WebDriver to wait when locating elements for the configured duration.
driver.manage()
.timeouts()
.implicitlyWait(
Duration.ofSeconds(5)
);
Implicit waits apply globally to element location calls. Selenium documents the default implicit wait as zero. :contentReference[oaicite:8]{index=8}
However, implicit waits are not a replacement for condition-specific synchronization when dealing with AJAX behavior.
46. Do Not Mix Implicit and Explicit Waits Carelessly
Selenium documentation warns against mixing implicit and explicit waits because their interaction can produce unpredictable timing behavior. :contentReference[oaicite:9]{index=9}
For data-driven and AJAX-heavy applications, many frameworks prefer a clear synchronization strategy centered on explicit waits for specific application conditions.
47. AJAX and Loading Spinners
A loading spinner is often an excellent synchronization point because it indicates that an asynchronous operation is in progress.
driver.findElement(By.id("loadData"))
.click();
wait.until(
ExpectedConditions.invisibilityOfElementLocated(
By.id("spinner")
)
);
WebElement data = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("data")
)
);
48. AJAX and Stale DOM
AJAX updates can replace a section of the DOM. Therefore, an element found before the update may no longer represent the current element after the update.
Old DOM
|
v
AJAX Update
|
v
Old Element Removed
|
v
New Element Created
|
v
New WebElement Reference Required
49. AJAX and Dynamic Tables
Dynamic tables may initially contain no rows and later receive data from an API.
driver.findElement(By.id("loadData"))
.click();
wait.until(
ExpectedConditions.presenceOfElementLocated(
By.cssSelector("#users tbody tr")
)
);
List<WebElement> rows = driver.findElements(
By.cssSelector("#users tbody tr")
);
for (WebElement row : rows) {
System.out.println(row.getText());
}
50. AJAX and File Upload Status
Some applications upload a file asynchronously and display an upload status after processing.
driver.findElement(By.id("file"))
.sendKeys(
"C:\\files\\document.pdf"
);
driver.findElement(By.id("upload"))
.click();
wait.until(
ExpectedConditions.textToBePresentInElementLocated(
By.id("uploadStatus"),
"Upload Complete"
)
);
51. AJAX and Auto-Save
Modern applications may automatically save changes in the background.
driver.findElement(By.id("title"))
.sendKeys("Selenium Notes");
wait.until(
ExpectedConditions.textToBePresentInElementLocated(
By.id("saveStatus"),
"Saved"
)
);
52. AJAX and Search Results
A common real-world Selenium scenario is testing an AJAX search component.
driver.findElement(By.id("search"))
.sendKeys("Selenium");
WebElement result = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.xpath(
"//div[contains(@class,'result') and contains(.,'Selenium')]"
)
)
);
result.click();
53. AJAX and Checkbox/Toggle Updates
Some applications send an AJAX request after a checkbox or toggle is changed.
driver.findElement(By.id("notificationToggle"))
.click();
wait.until(
ExpectedConditions.textToBePresentInElementLocated(
By.id("status"),
"Enabled"
)
);
54. AJAX and Delete Operations
Delete operations may remove an element from the DOM asynchronously.
WebElement row = driver.findElement(
By.id("userRow")
);
driver.findElement(By.id("delete"))
.click();
wait.until(
ExpectedConditions.stalenessOf(row)
);
Waiting for staleness can confirm that the previous element has been removed from the DOM.
55. AJAX and Refreshing Partial Content
Some applications refresh only a particular section instead of refreshing the whole page.
driver.findElement(By.id("refreshOrders"))
.click();
wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.cssSelector("#orders tbody tr")
)
);
56. AJAX and JavaScript Alerts
An asynchronous operation may eventually trigger a JavaScript alert. Selenium can wait for the alert before interacting with it.
driver.findElement(By.id("process"))
.click();
WebDriverWait wait = new WebDriverWait(
driver,
Duration.ofSeconds(10)
);
wait.until(
ExpectedConditions.alertIsPresent()
);
Alert alert = driver.switchTo().alert();
System.out.println(alert.getText());
alert.accept();
57. AJAX and Frames
If AJAX content is loaded inside an iframe, Selenium must first switch to the correct frame before interacting with elements inside it.
wait.until(
ExpectedConditions.frameToBeAvailableAndSwitchToIt(
By.id("paymentFrame")
)
);
WebElement cardNumber = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("cardNumber")
)
);
cardNumber.sendKeys("4111111111111111");
driver.switchTo().defaultContent();
58. AJAX and Windows/Tabs
Some asynchronous workflows may open a new tab or window after a user action. The automation should wait until the expected window appears before switching.
String originalWindow = driver.getWindowHandle();
driver.findElement(By.id("openWindow"))
.click();
wait.until(driver -> driver.getWindowHandles().size() > 1);
for (String window : driver.getWindowHandles()) {
if (!window.equals(originalWindow)) {
driver.switchTo().window(window);
break;
}
}
59. AJAX Synchronization Strategy
A reliable AJAX automation strategy should focus on the state that indicates the application is ready.
| Scenario | Recommended Synchronization |
| Element added dynamically | presenceOfElementLocated() |
| Element becomes visible | visibilityOfElementLocated() |
| Button becomes clickable | elementToBeClickable() |
| Text changes | textToBePresentInElementLocated() |
| Loading spinner disappears | invisibilityOfElementLocated() |
| Old DOM element replaced | stalenessOf() |
| Dynamic custom state | Custom lambda condition |
| Dynamic frame appears | frameToBeAvailableAndSwitchToIt() |
60. Complete AJAX Selenium Example
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class AjaxTest {
WebDriver driver;
WebDriverWait wait;
@BeforeMethod
public void setup() {
driver = new ChromeDriver();
driver.manage().window().maximize();
wait = new WebDriverWait(
driver,
Duration.ofSeconds(15)
);
driver.get("https://example.com");
}
@Test
public void ajaxSearchTest() {
WebElement search = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("search")
)
);
search.sendKeys("Selenium");
WebElement result = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.cssSelector(".search-result")
)
);
Assert.assertTrue(
result.isDisplayed()
);
result.click();
}
@AfterMethod
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
61. Complete AJAX Form Example
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class AjaxFormTest {
WebDriver driver;
WebDriverWait wait;
@BeforeMethod
public void setup() {
driver = new ChromeDriver();
wait = new WebDriverWait(
driver,
Duration.ofSeconds(15)
);
driver.get("https://example.com/form");
}
@Test
public void submitForm() {
driver.findElement(By.id("name"))
.sendKeys("John");
driver.findElement(By.id("email"))
.sendKeys("[email protected]");
driver.findElement(By.id("submit"))
.click();
wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.id("successMessage")
)
);
String message = driver.findElement(
By.id("successMessage")
).getText();
Assert.assertEquals(
message,
"Registration Successful"
);
}
@AfterMethod
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
62. AJAX with Page Object Model
In a Page Object Model framework, synchronization logic can be encapsulated inside page classes so that test classes remain clean.
public class SearchPage {
private WebDriver driver;
private WebDriverWait wait;
private By searchBox =
By.id("search");
private By searchResult =
By.cssSelector(".search-result");
public SearchPage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(
driver,
Duration.ofSeconds(10)
);
}
public void search(String text) {
WebElement search =
wait.until(
ExpectedConditions
.visibilityOfElementLocated(searchBox)
);
search.sendKeys(text);
}
public void selectResult() {
WebElement result =
wait.until(
ExpectedConditions
.elementToBeClickable(searchResult)
);
result.click();
}
}
63. AJAX POM Test
public class SearchTest {
WebDriver driver;
SearchPage searchPage;
@BeforeMethod
public void setup() {
driver = new ChromeDriver();
driver.get("https://example.com");
searchPage =
new SearchPage(driver);
}
@Test
public void searchTest() {
searchPage.search("Selenium");
searchPage.selectResult();
}
@AfterMethod
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
64. AJAX and Data-Driven Testing
AJAX functionality can be combined with TestNG Data Providers to test the same dynamic workflow using multiple data sets.
@DataProvider(name = "searchData")
public Object[][] searchData() {
return new Object[][] {
{"Selenium"},
{"Java"},
{"TestNG"},
{"Automation"}
};
}
@Test(dataProvider = "searchData")
public void searchTest(String keyword) {
driver.findElement(By.id("search"))
.sendKeys(keyword);
WebElement result = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.cssSelector(".search-result")
)
);
Assert.assertTrue(
result.isDisplayed()
);
}
65. AJAX and Test Reports
AJAX-related failures should be clearly reported because synchronization problems can otherwise be difficult to diagnose.
Useful information to capture includes:
- Test method name.
- Input data.
- Locator involved.
- Expected condition.
- Actual application state.
- Exception message.
- Screenshot at failure.
- Current URL.
- Browser information.
- Relevant console or application logs where available.
66. Common AJAX Exceptions
| Exception | Possible Cause | Typical Solution |
| NoSuchElementException | Element not yet present | Wait for presence |
| ElementNotInteractableException | Element exists but is not ready | Wait for visibility/interactability |
| ElementClickInterceptedException | Another element or overlay blocks click | Wait for overlay/state and clickability |
| StaleElementReferenceException | DOM element was replaced | Wait for update and locate element again |
| TimeoutException | Condition was not satisfied in time | Check application state, locator, and timeout |
67. Common Mistakes with AJAX Elements
- Using Thread.sleep() everywhere.
- Assuming page load completion means AJAX completion.
- Using an element reference after the DOM has been refreshed.
- Using unstable dynamic locators.
- Waiting for the wrong condition.
- Using very short explicit wait timeouts for slow environments.
- Using very long timeouts for every operation.
- Mixing implicit and explicit waits without understanding their interaction.
- Sharing WebDriver instances between parallel tests.
- Using JavaScript clicks as a first solution instead of fixing synchronization.
- Ignoring loading overlays.
- Failing to identify which AJAX operation caused the failure.
68. Best Practices for AJAX Elements
- Prefer explicit waits for specific dynamic conditions.
- Wait for the state that actually indicates readiness.
- Use stable and meaningful locators.
- Avoid unnecessary Thread.sleep() calls.
- Re-locate elements after DOM replacement.
- Wait for loading indicators to disappear when appropriate.
- Use Expected Conditions for common synchronization scenarios.
- Use custom wait conditions for application-specific states.
- Keep synchronization logic reusable in Page Objects.
- Use appropriate timeout values based on the application and environment.
- Keep parallel Selenium execution thread-safe.
- Capture useful diagnostic information when synchronization fails.
69. AJAX Element Testing Strategy
Identify Dynamic Behavior
|
v
Identify Application State
|
v
Choose Stable Locator
|
v
Choose Expected Condition
|
v
Apply Explicit Wait
|
v
Locate Current Element
|
v
Perform Action
|
v
Validate Result
|
v
Capture Report
70. Real-World E-Commerce AJAX Example
Consider an e-commerce application where a user searches for a product, selects a suggestion, adds the product to the cart, and waits for the cart count to update.
driver.findElement(By.id("search"))
.sendKeys("Laptop");
WebElement suggestion = wait.until(
ExpectedConditions.elementToBeClickable(
By.cssSelector(".suggestion")
)
);
suggestion.click();
WebElement addToCart = wait.until(
ExpectedConditions.elementToBeClickable(
By.id("addToCart")
)
);
addToCart.click();
wait.until(
ExpectedConditions.textToBePresentInElementLocated(
By.id("cartCount"),
"1"
)
);
Assert.assertEquals(
driver.findElement(By.id("cartCount")).getText(),
"1"
);
71. Real-World AJAX Workflow
Open E-Commerce Application
|
v
Enter Product Search
|
v
AJAX Search Request
|
v
Wait for Suggestions
|
v
Select Product
|
v
Wait for Product Details
|
v
Click Add to Cart
|
v
AJAX Cart Update
|
v
Wait for Cart Count
|
v
Verify Cart
|
v
Test Pass/Fail
72. AJAX Elements and Synchronization Comparison
| Technique | Use | Suitability for AJAX |
| Thread.sleep() | Fixed delay | Limited |
| Implicit Wait | Global element-location wait | Useful for basic synchronization |
| Explicit Wait | Wait for a specific condition | Highly useful |
| Expected Conditions | Common application states | Highly useful |
| FluentWait | Custom timeout/polling behavior | Useful for advanced cases |
| Custom Lambda | Application-specific condition | Useful for complex dynamic states |
73. AJAX vs Explicit Wait
AJAX itself is not a Selenium waiting mechanism. AJAX is an application-side technique for asynchronous communication and dynamic updates. Selenium's job is to synchronize with the application's resulting state.
AJAX
|
|-- Changes application state
|
v
Dynamic DOM / UI
|
v
Selenium Wait
|
v
Required Condition
|
v
Selenium Action
74. Practical Exercises
- Automate an AJAX search box with dynamic suggestions.
- Wait for a dynamically populated table.
- Automate a dependent country-state dropdown.
- Test an AJAX login form.
- Wait for a loading spinner to disappear.
- Automate an AJAX add-to-cart operation.
- Handle a dynamic modal window.
- Handle a stale element after an AJAX refresh.
- Wait for dynamically updated status text.
- Use a custom Expected Condition for an application-specific state.
- Build an AJAX test using Page Object Model.
- Combine AJAX automation with a TestNG Data Provider.
75. Interview Questions on AJAX Elements
1. What is AJAX?
AJAX is a technique that allows web applications to exchange data asynchronously and update portions of a page without a complete page reload.
2. Why are AJAX elements difficult to automate?
Because the element or its state may change asynchronously after the initial page has loaded.
3. Which wait is commonly useful for AJAX elements?
Explicit Wait is commonly used because it allows Selenium to wait for a specific application condition.
4. What is the difference between presence and visibility?
Presence means an element exists in the DOM. Visibility means the element is displayed and available for visual interaction.
5. What is an AJAX loading spinner?
It is a visual indicator showing that an asynchronous operation is still processing.
6. How can you wait for a spinner to disappear?
Use an explicit wait with an invisibility condition.
7. What causes StaleElementReferenceException in AJAX applications?
An AJAX update may replace or remove the DOM element represented by the old WebElement reference.
8. How can stale elements be handled?
Wait for the DOM update when appropriate and locate the current element again.
9. Can document.readyState guarantee that AJAX content is ready?
No. JavaScript-driven asynchronous updates can continue after the initial document reaches its ready state. :contentReference[oaicite:10]{index=10}
10. Should Thread.sleep() be used for every AJAX operation?
No. Condition-based explicit waits are generally more reliable and efficient.
11. What is ExpectedConditions?
ExpectedConditions provides reusable conditions for explicit waits, such as visibility, presence, clickability, text, title, and staleness.
12. What is FluentWait?
FluentWait allows customization of timeout, polling interval, and ignored exceptions.
13. Can AJAX elements cause NoSuchElementException?
Yes. If Selenium searches before the dynamically created element is available, the element may not be found.
14. Can AJAX cause ElementNotInteractableException?
Yes. An element may exist but not yet be visible or ready for interaction.
15. How do you automate AJAX search suggestions?
Enter the search text, wait for the suggestion element to become visible or clickable, and then interact with the current suggestion.
16. How do you handle an AJAX-updated table?
Wait for the required table row or data condition and then locate the current rows.
17. How do you handle AJAX-dependent dropdowns?
Select the parent value, wait for the dependent options to load, and then select the required option.
18. Can AJAX testing be combined with POM?
Yes. Page Objects can encapsulate AJAX synchronization and application interaction logic.
19. Can AJAX testing be combined with Data Providers?
Yes. TestNG Data Providers can supply multiple input combinations to AJAX-based test methods.
20. What is the most important principle when automating AJAX applications?
Synchronize with the application's actual state instead of relying on arbitrary fixed delays.
76. Quick Reference Table
| Concept | Description |
| AJAX | Asynchronous communication and dynamic page updates |
| Dynamic Element | Element that can appear or change after initial page load |
| Explicit Wait | Waits for a specific condition |
| presenceOfElementLocated() | Waits for DOM presence |
| visibilityOfElementLocated() | Waits for visibility |
| elementToBeClickable() | Waits until an element is clickable |
| textToBePresentInElementLocated() | Waits for specific text |
| invisibilityOfElementLocated() | Waits for an element to become invisible |
| stalenessOf() | Waits for an old element to detach from DOM |
| FluentWait | Custom timeout and polling behavior |
| Thread.sleep() | Fixed delay; generally less reliable for dynamic synchronization |
| Page Object Model | Can encapsulate AJAX synchronization logic |
77. Learning Roadmap for AJAX Elements
- Understand HTML DOM and JavaScript basics.
- Understand AJAX and asynchronous communication.
- Learn Selenium element locators.
- Understand static and dynamic elements.
- Learn implicit waits.
- Learn explicit waits.
- Learn Expected Conditions.
- Practice visibility and clickability conditions.
- Learn to handle loading spinners.
- Handle AJAX search suggestions.
- Handle dynamic dropdowns and tables.
- Understand StaleElementReferenceException.
- Learn FluentWait and custom conditions.
- Integrate AJAX synchronization with Page Object Model.
- Combine AJAX tests with TestNG Data Providers.
- Build a reusable Selenium framework for modern dynamic applications.
78. Summary
AJAX elements are common in modern web applications because JavaScript can dynamically load, modify, replace, or display content without performing a complete page refresh.
For Selenium automation, the main challenge is synchronization. The test may execute before the application has finished its asynchronous operation. Selenium's documentation identifies these timing differences as a common source of flaky tests and recommends synchronization mechanisms such as explicit waits. :contentReference[oaicite:11]{index=11}
Explicit waits and Expected Conditions allow Selenium to wait for meaningful states such as element presence, visibility, clickability, expected text, disappearance of a loading indicator, or replacement of an old DOM element. :contentReference[oaicite:12]{index=12}
Reliable AJAX automation should avoid unnecessary fixed delays, use stable locators, re-locate elements after DOM updates, handle stale references appropriately, and keep synchronization logic organized within reusable Page Objects.
79. Course Resources
Learn more about Selenium automation and related testing concepts:
Final Takeaway: AJAX automation is primarily a synchronization challenge. Instead of guessing how long an asynchronous operation will take, Selenium tests should wait for the specific application state required before performing the next action. This makes tests more stable, readable, maintainable, and suitable for modern dynamic web applications.